package jjwt.study.Config;

import jjwt.study.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import java.util.ArrayList;
import java.util.List;

/**
 * 描述:授权服务器配置
 *
 * @author Ychiha
 * @version 1.0
 * @date 14/1/2022 下午6:19
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig  extends AuthorizationServerConfigurerAdapter {

    //加密
    @Autowired
    private PasswordEncoder passwordEncoder;

    //授权的密码模式 需要注入的类
    @Autowired
    private AuthenticationManager authenticationManager;

    //授权的密码模式 需要注入的类
    @Autowired
    private UserService userService;

    //jwt
    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore tokenStore;

    //access与Token相互转换
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    //jwt内容增加器
    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;



    /**
     * 权限代理
     * 直接通过AuthenticationManager将密码发送到资源服务器
     * 需要注入AuthenticationManager、UserService
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        //  配置 JWT 内容增强器
        TokenEnhancerChain enhancer = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        enhancer.setTokenEnhancers(delegates);

        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userService)
                //配置存储令牌策略
                .tokenStore(tokenStore)
                //access与Token相互转换
                .accessTokenConverter(jwtAccessTokenConverter)
                .tokenEnhancer(enhancer);
    }

    /**
     * 重写Client为参的configure方法
     * 授权服务器的配置
     * 授权者模式:
     * 访问网址:localhost:8080/oauth/authorize?response_type=code&client_id=yzm&redirect_uri=http://www.baidu.com&scope=all
     * 要先去上面的访问地址拿到授权服务器的授权码（code）才能往下继续操作
     * 拿到授权码后，发送 http://localhost:8080/oauth/token  POST 请求，选择 Basic Auth，输入账号密码
     * 再选择 body 类型下的 x-www-form-urlencoded ，写上参数，参数如下：
     * grant_type ：authorization_code
     * code : 上述拿到的授权码
     * client_id ：admin
     * redirect_uri ：http://www.baidu.com
     * scope ：all
     * 上面的 grant_type  client_id  redirect_uri  scope 都是下面配置的，然后才能拿到 access_token
     *
     * 接着再向 http://localhost:8080/user/getCurrentUser 发送 POST 请求
     *             选择 Bearer Token 输入 access_token
     *             然后才能拿到对应的用户信息
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("yzm")
                //配置client-secret
                .secret(passwordEncoder.encode("123"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新令牌的有效期
                .refreshTokenValiditySeconds(864000)
                //自动授权
                .autoApprove(true)
                //配置redirect_uri，授权成功后跳转
//                .redirectUris("http://www.baidu.com") //跳转后留意uri后面的?code=JxzMH8 此为授权码
                .redirectUris("http://localhost:8081/login")
                //配置申请的权限范围
                .scopes("all")
                /*
                  配置 grant_type，表示授权类型:
                    authorization_code 授权码模式
                    password 密码模式
                */
//                .authorizedGrantTypes("authorization_code");
//                .authorizedGrantTypes("password");

                /**
                 * 刷新令牌 refresh_token
                    下述配置表示即支持授权码模式，也支持密码模式

                    拿到授权码后，发送 http://localhost:8080/oauth/token  POST 请求，选择 Basic Auth，输入账号密码
                       再选择 body 类型下的 x-www-form-urlencoded ，写上参数，参数如下：
                       grant_type ：refresh_token
                       refresh_token ：拿到的刷新令牌
                */
                .authorizedGrantTypes("password", "refresh_token", "authorization_code");
    }




    /**
     * 单点登录必须配置
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //  获取密钥需要身份认证,使用单点登录时必须配置
        security.tokenKeyAccess("isAuthenticated()");
    }


    /**
     * 授权模式使用密码模式所需配置
     *
     * 此时直接发送 http://localhost:8080/oauth/token  POST 请求，选择 Basic Auth，输入账号密码
     * 再选择 body 类型下的 x-www-form-urlencoded ，写上参数，参数如下：
     * grant_type ：password
     * username ：admin
     * scope ：all
     * 上面的 grant_type  scope username 都是下面配置的，然后才能拿到 access_token
     *
     * 紧接着再向 http://localhost:8080/user/getCurrentUser 发送 POST 请求
     * 选择 Bearer Token 输入 access_token
     * 然后才能拿到对应的用户信息
     *
     * @param endpoints
     * @throws Exception
     */

}
